package com.xq.springboot.realm;

import com.xq.springboot.common.ActiverUser;
import com.xq.springboot.pojo.User;
import com.xq.springboot.service.PermissionService;
import com.xq.springboot.service.RoleService;
import com.xq.springboot.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * @author xq
 * @version 1.0
 * @date 2021/4/19 9:00
 * @description 用户的授权领域类
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

    /**
     * 给用户认证
     * @param token 认证对象
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 获取用户名，根据用户名查询用户对象
        String userName = token.getPrincipal().toString();
        // 根据用户名查询用户对象
        User userByUserName = this.userService.getUserByUserName(userName);
        if (userByUserName != null) {
            ActiverUser activerUser = new ActiverUser();
            // 将用户对象注入到组合对象中
            activerUser.setUser(userByUserName);
            // 根据用户Id查询角色
            List<String> rolesByUserId = this.roleService.getRolesByUserId(userByUserName.getUserId());
            // 根据用户Id查询权限
            List<String> permissionByUserId = this.permissionService.getPermissionByUserId(userByUserName.getUserId());
            // 将角色集合和权限集合注入到组合对象中
            activerUser.setRoles(rolesByUserId);
            activerUser.setPermissions(permissionByUserId);
            // 根据用户名和地址进行对密码的散列加密，获取凭据盐对象
            ByteSource credentialsSalt = ByteSource.Util.bytes(userByUserName.getUserName() + userByUserName.getAddress());
            // 获取认证对象
            // 参数1：传输对象，可以传递到doGetAuthorizationInfo()方法中，也可以传到subject.getPrincipal()
            // 参数2：加密后的字符串（密码）
            // 参数3：加密后的盐
            // 参数4：当前类名
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                    activerUser,userByUserName.getUserPassword(),credentialsSalt,getName()
            );
            return info;
        }
        return null;
    }

    /**
     * 给用户授权
     * @param principals 身份验证对象
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 从认证的方法，获取传输的ActiverUser对象
        ActiverUser activerUser = (ActiverUser) principals.getPrimaryPrincipal();
        // 创建授权对象
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 获取登录的用户的角色集合
        List<String> roles = activerUser.getRoles();
        // 获取登录的用户的权限集合
        List<String> permissions = activerUser.getPermissions();
        // 如果角色集合不为空，则将角色集合添加到授权对象中
        if(roles != null && roles.size() > 0) {
            info.addRoles(roles);
        }
        // 如果权限集合不为空，则将权限集合添加到授权对象中
        if(permissions != null && permissions.size() > 0) {
            info.addStringPermissions(permissions);
        }
        // 如果返回空，代表当前主体没有任何角色或权限信息
        return info;
    }
}
